/****************************************************************/
/*                                                              */
/*       K&R Unit: C programming language test framework        */
/*                                                              */
/*  Copyright 09.12.2010 Alexey A. Popov. All rights reserved.  */
/*                                                              */
/*    This program contains the confidential trade secret       */
/*    information of Alexey A. Popov.  Use, disclosure, or      */
/*    copying without written consent is strictly prohibited.   */
/*                                                              */
/****************************************************************/

/*! \file kru.h
	\brief K&R Unit: C programming language test framework.
 */

#ifndef __kru_h__
#define __kru_h__

#include <stdlib.h>
#include <string.h>
#include <math.h>

/*!	\fn void* kru_malloc(size_t size)
	\brief A safer memory allocation function.
	\param size the size of the memory block to allocate.
	\return A pointer to a new memory block.
	\warning May abort test program execution.

    This function alocates memory with standard malloc
    function and checks if the result is NULL, i. e.
	if the program runs out of memory. In this case it prints
	out an error message and quits because it is no use to
    continue testing the memory leaking code.
*/
extern /*@notnull@*/ /*@out@*/ void* kru_malloc(size_t size);

/*! \fn void* kru_calloc(size_t n, size_t size)
	\brief A safer memory allocation function.
	\param n - number of elements to allocate.
	\param size - size in bytes of an element.
	\return A pointer to a new memory block.
	\warning May abort test program execution.

    This function alocates zeroed memory with standard
    calloc function and checks if the result is NULL,
    i. e. the program run out of memory. In this case
    it prints an error message and quits because it is
    no use to continue testing the memory leaking code.
*/
extern /*@notnull@*/ void* kru_calloc(size_t n, size_t size);

/*! \fn void* kru_realloc(void *oldptr, size_t size)
	\brief A safer memory reallocation function.
	\param oldptr The pointer to the old memory block.
	\param size The new size of the memory block.
	\return A pointer to a new memory block OR the same but resized block.
	\warning May abort test program execution.

    This function realocates memory with standard realloc
    function and checks if the result is NULL, i. e.
    the program run out of memory. In this case it prints
    an error message and quits because it is no use to
    continue testing the memory leaking code.
*/
extern /*@notnull@*/ void* kru_realloc(/*@null@*/ /*@out@*/ void *oldptr, size_t size);

/*! \def malloc
	\brief Redefines the RTL malloc routine.
	\see kru_malloc
	\warning Be careful, such renames make code hairy!
*/
#define malloc kru_malloc

/*! \def calloc
	\brief Redefines the RTL calloc routine.
	\see kru_calloc
	\warning Be careful, such renames make code hairy!
*/
#define calloc kru_calloc

/*! \def realloc
	\brief Redefines the RTL realloc routine.
	\see kru_realloc
	\warning Be careful, such renames make code hairy!
*/
#define realloc kru_realloc

/*
 */
/*! \def kru_free
	\brief Defines kru_free as the RTL free routine.

	This macro provided for name uniformity only.
*/
#define kru_free free

/*
	Main assertion routine
 */
/*! \fn kru_assert(int condition, int abortTest, const char* file, int line, const char* message)
	\brief The main assertion routine.
    \param condition The assertion's condition.
    \param abortTest If this is non 0, the test will be aborted.
    \param file The name of the source file where the assertion is placed.
    \param line The line where the assertion is placed.
    \param message An optional message for the user.

    All KRU_ASSERT_xxx macros along with KRU_PASS and KRU_FAIL
    call this routine.
    This function might perform a non-local jump back to
    the test runner effectively aborting the test run.
    Also, it might abort execution in case the 'runningTest'
    global is somehow corrupted.
*/
extern void kru_assert(int condition, int abortTest, const char* file, int line, const char* message);

/*
	Various assertion. NB: Add new ones here!
	'_FATAL' here means - abort the test.
 */
/*! \def KRU_PASS(__msg)
	\brief Output message and pass the test
	\param __msg The message to output.
*/
#define KRU_PASS(__msg)	\
	kru_assert(1, 0, __FILE__, __LINE__, __msg)

/*! \def KRU_FAIL(__msg)
	\brief Output message and fail the test
	\param __msg The message to output.
*/
#define KRU_FAIL(__msg)	\
	kru_assert(0, 0, __FILE__, __LINE__, __msg)

/*! \def KRU_FATAL(__msg)
	\brief Output message and abort the test
	\param __msg The message to output.
*/
#define KRU_FATAL(__msg)	\
	kru_assert(0, 1, __FILE__, __LINE__, __msg)

/*! \def KRU_ASSERT(__cond)
	\brief Check condition and report an error in case it's not satisfied.
	\param __cond The condition to check.
*/
#define KRU_ASSERT(__cond)	\
	kru_assert((__cond), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_FATAL(__cond)
	\brief Check condition and abort the test in case it's not satisfied.
	\param __cond The condition to check.
	\warning If condition is not satisfied, the code below the assertion
	up until end of the test function is not executed.
*/
#define KRU_ASSERT_FATAL(__cond)	\
	kru_assert((__cond), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_TRUE(__cond)
	\brief Check if condition is true.
	\param __cond The condition to check.
*/
#define KRU_ASSERT_TRUE(__cond)	\
	kru_assert((__cond), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_TRUE_FATAL(__cond)
	\brief Check if condition is true and aborts the test otherwise.
	\param __cond The condition to check.
	\warning If condition is not satisfied, the code below the assertion
	up until end of the test function is not executed.
*/
#define KRU_ASSERT_TRUE_FATAL(__cond)	\
	kru_assert((__cond), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_FALSE(__cond)
	\brief Check if condition is false.
	\param __cond The condition to check.
*/
#define KRU_ASSERT_FALSE(__cond)	\
	kru_assert(!(__cond), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_FALSE_FATAL(__cond)
	\brief Check if condition is false and abort the test otherwise.
	\param __cond The condition to check.
	\warning If condition is not satisfied, the code below the assertion
	up until end of the test function is not executed.
*/
#define KRU_ASSERT_FALSE_FATAL(__cond)	\
	kru_assert(!(__cond), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_EQUAL(__val, __exp)
	\brief Check if a value is equal to the expected value.
	\param __val The value to check.
	\param __exp The expected value.
*/
#define KRU_ASSERT_EQUAL(__val, __exp)	\
	kru_assert((__val)==(__exp), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_EQUAL_FATAL(__val, __exp)
	\brief Check if a value is equal to the expected value,
	and abort the test in case it's not satisfied.
	\param __val The value to check.
	\param __exp Expected value.
	\warning If value is not equal to expected value, the code
	below the assertion up until end of the test function is
	not executed.
*/
#define KRU_ASSERT_EQUAL_FATAL(__val, __exp)	\
	kru_assert((__val)==(__exp), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_NOT_EQUAL(__val, __exp)
	\brief Check if a value is not equal to the expected value.
	\param __val The value to check.
	\param __exp The expected value.
*/
#define KRU_ASSERT_NOT_EQUAL(__val, __exp)	\
	kru_assert((__val)!=(__exp), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_NOT_EQUAL_FATAL(__val, __exp)
	\brief Check if a value is not equal to the expected value,
	and abort the test in case it's not satisfied.
	\param __val The value to check.
	\param __exp Expected value.
	\warning If value is equal to expected value, the code
	below the assertion up until end of the test function is
	not executed.
*/
#define KRU_ASSERT_NOT_EQUAL_FATAL(__val, __exp)	\
	kru_assert((__val)!=(__exp), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_PTR_EQUAL(__ptr, __exp)
	\brief Check if a pointer is equal to the expected pointer.
	\param __ptr The pointer to check.
	\param __exp The expected pointer.
*/
#define KRU_ASSERT_PTR_EQUAL(__ptr, __exp)	\
	kru_assert(((void*)(__ptr))==((void*)(__exp)), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_PTR_EQUAL_FATAL(__ptr, __exp)
	\brief Check if a pointer is equal to the expected pointer,
	and abort the test in case it's not satisfied.
	\param __ptr The pointer to check.
	\param __exp The expected pointer.
	\warning If value is equal to expected value, the code
	below the assertion up until end of the test function is
	not executed.
*/
#define KRU_ASSERT_PTR_EQUAL_FATAL(__ptr, __exp)	\
	kru_assert(((void*)(__ptr))==((void*)(__exp)), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_PTR_NOT_EQUAL(__ptr, __exp)
	\brief Check if a pointer is not equal to the expected pointer.
	\param __ptr The pointer to check.
	\param __exp The expected pointer.
*/
#define KRU_ASSERT_PTR_NOT_EQUAL(__ptr, __exp)	\
	kru_assert(((void*)(__ptr))!=((void*)(__exp)), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_PTR_NOT_EQUAL_FATAL(__ptr, __exp)
	\brief Check if a pointer is not equal to the expected pointer,
	and abort the test in case it's not satisfied.
	\param __ptr The pointer to check.
	\param __exp The expected pointer.
	\warning If value is equal to expected value, the code
	below the assertion up until end of the test function is
	not executed.
*/
#define KRU_ASSERT_PTR_NOT_EQUAL_FATAL(__ptr, __exp)	\
	kru_assert(((void*)(__ptr))!=((void*)(__exp)), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_PTR_NULL(__ptr)
	\brief Check if a pointer is NULL.
	\param __ptr The pointer to check.
*/
#define KRU_ASSERT_PTR_NULL(__ptr)	\
	kru_assert(NULL==(__ptr), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_PTR_NULL_FATAL(__ptr)
	\brief Check if a pointer is NULL and abort the test
	in case it's not satisfied.
	\param __ptr The pointer to check.
	\warning If value is equal to expected value, the code
	below the assertion up until end of the test function is
	not executed.
*/
#define KRU_ASSERT_PTR_NULL_FATAL(__ptr)	\
	kru_assert(NULL==(__ptr), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_PTR_NOT_NULL(__ptr)
	\brief Check if a pointer is not NULL.
	\param __ptr The pointer to check.
*/
#define KRU_ASSERT_PTR_NOT_NULL(__ptr)	\
	kru_assert(NULL!=(__ptr), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_PTR_NOT_NULL_FATAL(__ptr)
	\brief Check if a pointer is not NULL and abort the test
	in case it's not satisfied.
	\param __ptr The pointer to check.
	\warning If value is equal to expected value, the code
	below the assertion up until end of the test function is
	not executed.
*/
#define KRU_ASSERT_PTR_NOT_NULL_FATAL(__ptr)	\
	kru_assert(NULL!=(__ptr), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_STR_EQUAL(__str, __exp)
	\brief Check if a string is equal to the expected string.
	\param __str The string to check.
	\param __exp The expected string.
*/
#define KRU_ASSERT_STR_EQUAL(__str, __exp)	\
	kru_assert(0==strcmp((__str), (__exp)), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_STR_EQUAL_FATAL(__str, __exp)
	\brief Check if a string is equal to the expected string
	and abort the test in case it's not satisfied.
	\param __str The string to check.
	\param __exp The expected string.
	\warning If the string is not equal to expected string,
	the code below the assertion up until end of the test
	function is not executed.
*/
#define KRU_ASSERT_STR_EQUAL_FATAL(__str, __exp)	\
	kru_assert(0==strcmp((__str), (__exp)), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_STR_NOT_EQUAL(__str, __exp)
	\brief Check if a string is not equal to the expected string.
	\param __str The string to check.
	\param __exp The expected string.
*/
#define KRU_ASSERT_STR_NOT_EQUAL(__str, __exp)	\
	kru_assert(0!=strcmp((__str), (__exp)), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_STR_NOT_EQUAL_FATAL(__str, __exp)
	\brief Check if a string is not equal to the expected string
	and abort the test in case it's not satisfied.
	\param __str The string to check.
	\param __exp The expected string.
	\warning If the string is not equal to expected string,
	the code below the assertion up until end of the test
	function is not executed.
*/
#define KRU_ASSERT_STR_NOT_EQUAL_FATAL(__str, __exp)	\
	kru_assert(0!=strcmp((__str), (__exp)), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_ISTR_EQUAL(__str, __exp)
	\brief Check if a string is equal to the expected string,
	ignoring case.
	\param __str The string to check.
	\param __exp The expected string.
*/
#define KRU_ASSERT_ISTR_EQUAL(__str, __exp)	\
	kru_assert(0==_stricmp((__str), (__exp)), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_ISTR_EQUAL_FATAL(__str, __exp)
	\brief Check if a string is equal to the expected string,
	ignoring case, and abort the test in case it's not satisfied.
	\param __str The string to check.
	\param __exp The expected string.
	\warning If the string is not equal to expected string,
	the code below the assertion up until end of the test
	function is not executed.
*/
#define KRU_ASSERT_ISTR_EQUAL_FATAL(__str, __exp)	\
	kru_assert(0==_stricmp((__str), (__exp)), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_ISTR_NOT_EQUAL(__str, __exp)
	\brief Check if a string is not equal to the expected string,
	ignoring case
	\param __str The string to check.
	\param __exp The expected string.
*/
#define KRU_ASSERT_ISTR_NOT_EQUAL(__str, __exp)	\
	kru_assert(0!=_stricmp((__str), (__exp)), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_ISTR_NOT_EQUAL_FATAL(__str, __exp)
	\brief Check if a string is not equal to the expected string,
	ignoring case, and abort the test in case it's not satisfied.
	\param __str The string to check.
	\param __exp The expected string.
	\warning If the string is not equal to expected string,
	the code below the assertion up until end of the test
	function is not executed.
*/
#define KRU_ASSERT_ISTR_NOT_EQUAL_FATAL(__str, __exp)	\
	kru_assert(0!=_stricmp((__str), (__exp)), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_DBL_EQUAL(__val, __exp, __dev)
	\brief Check if a float value is equal to the expected
	one, taking in account deviation.
	\param __val The value to check.
	\param __exp The expected value.
	\param __dev The acceptable deviation.
*/
#define KRU_ASSERT_DBL_EQUAL(__val, __exp, __dev)	\
	kru_assert(fabs((__val)-(__exp))<fabs(__dev), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_DBL_EQUAL_FATAL(__val, __exp, __dev)
	\brief Check if a float value is equal to the expected
	one, taking in account deviation, and abort the test
	in case it's not satisfied.
	\param __val The value to check.
	\param __exp The expected value.
	\param __dev The acceptable deviation.
	\warning If the value is not equal to the expected value,
	the code below the assertion up until end of the test
	function is not executed.
*/
#define KRU_ASSERT_DBL_EQUAL_FATAL(__val, __exp, __dev)	\
	kru_assert(fabs((__val)-(__exp))<fabs(__dev), 1, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_DBL_NOT_EQUAL(__val, __exp, __dev)
	\brief Check if a float value is not equal to the expected
	one, taking in account deviation.
	\param __val The value to check.
	\param __exp The expected value.
	\param __dev The acceptable deviation.
*/
#define KRU_ASSERT_DBL_NOT_EQUAL(__val, __exp, __dev)	\
	kru_assert(fabs((__val)-(__exp))>fabs(__dev), 0, __FILE__, __LINE__, NULL)

/*! \def KRU_ASSERT_DBL_NOT_EQUAL_FATAL(__val, __exp, __dev)
	\brief Check if a float value is not equal to the expected
	one, taking in account deviation, and abort the test
	in case it's not satisfied.
	\param __val The value to check.
	\param __exp The expected value.
	\param __dev The acceptable deviation.
	\warning If the value is not equal to the expected value,
	the code below the assertion up until end of the test
	function is not executed.
*/
#define KRU_ASSERT_DBL_NOT_EQUAL_FATAL(__val, __exp, __dev)	\
	kru_assert(fabs((__val)-(__exp))>fabs(__dev), 1, __FILE__, __LINE__, NULL)

/*! \typedef kru_test_setup_proc
	\brief Test set up function pointer.
	\param testData The pointer to the test data structure.
	\see kru_suite_setup_proc
	\return 1 on success, 0 on failure.

	This function may set up values in the test data structure
	allocated by kru_suite_setup_proc. This function must not
	deallocate the data structure.
 */
typedef int (*kru_test_setup_proc)(void *testData);
/*! \typedef kru_test_teardown_proc
	\brief Test tear down procedure pointer.
	\param testData The pointer to the test data structure.
	\see kru_suite_setup_proc
	\return 1 on success, 0 on failure.

	This function may free up resources used by the test. This
	function must not deallocate the data structure.
 */
typedef int (*kru_test_teardown_proc)(void *testData);
/*! \typedef kru_test_fixture
	\brief Test fixture procedure pointer.
	\param testData The pointer to the test data structure.
	\see kru_suite_setup_proc
	\warning May not return.

	This function may use the test data structure.
 */
typedef void (*kru_test_fixture)(void *testData);

/*! \typedef kru_test
	\brief Test
	\see kru_suite_setup_proc
 */
typedef struct kru_test kru_test;

/*! \typedef kru_suite
	\brief Test suite

	An opaque type.
 */
typedef struct kru_suite kru_suite;

/*! \typedef kru_registry
	\brief Test registry.

	An opaque type.
 */
typedef struct kru_registry kru_registry;

extern const char *SuiteSetUpFailed;

/*! \typedef kru_suite_setup_proc
	\brief Test suite set up function pointer.
	\return A pointer to the test data; may be NULL.

	This function may allocate memory for the tests data and return it.
	If the tests don't require it (either they don't use it at all or
	use globals) the function must return NULL. If the function has
	allocated the memory, it has to be deleted by respective tear down
	procedure.
	If there was an error, the function has to return SuiteSetUpFailed
	value;
 */
typedef void* (*kru_suite_setup_proc)(void);

/*! \typedef kru_suite_teardown_proc
	\brief Test suite tear down procedure pointer.
	\param testData The test data to be disposed of.
 */
typedef int (*kru_suite_teardown_proc)(void *testData);

/*! \fn kru_test* kru_suite_add_new_test(kru_suite *self, const char* name, kru_test_setup_proc setup, kru_test_fixture test, kru_test_teardown_proc teardown)
	\brief Creates and adds a new test to the test suite.
    \param self A pointer to the test suite; must be provided.
	\param name The name of the new test; optional, may be NULL.
    \param setup The test's set up routine; optional, may be NULL.
    \param test The test fixture; must be provided.
    \param teardown The test tear down routine; optional, may be NULL.
	\return An opaque pointer to the newly created test.

    This function creates a new test suite and adds it to
    the end of the tests list.
*/
extern /*@shared@*/ /*@notnull@*/ kru_test* kru_suite_add_new_test(/*@shared@*/ kru_suite *self, const char* name, kru_test_setup_proc setup, /*@notnull@*/ kru_test_fixture test, kru_test_teardown_proc teardown);

/*! \fn kru_registry* kru_registry_new(const char *name)
	\brief Creates a new test registry.
	\param name The name for the registry; optional, may be NULL.
	\return An opaque pointer to the new registry.

    This function creates a new, empty, test registry.
*/
extern /*@notnull@*/ kru_registry* kru_registry_new(const char *name);

/*! \fn void kru_registry_delete(kru_registry *self)
	\brief Deletes the test registry.
    \param self The registry to delete.

    This function releases the registry with all the tests
    and test suites in it.
*/
extern void kru_registry_delete(/*@out@*/ /*@notnull@*/ kru_registry *self) /*@modifies self@*/;

/*! \fn kru_suite* kru_registry_add_new_suite(kru_registry *self, const char *name, kru_suite_setup_proc setup, kru_suite_teardown_proc teardown)
	\brief Adds a new test suite to the test registry.
    \param self The registry to add the new suite to; must be provided.
    \param name The name of the suite; optional, may be NULL.
    \param setup The suite set up routine; optional, may be NULL.
    \param teardown The suite tear down routine; optional, may be NULL.
    \return An opaque pointer to the new test suite.

    This function creates a new test suite and adds it to the
    end of the registry's test suites list.
*/
extern /*@notnull@*/ kru_suite* kru_registry_add_new_suite(/*@notnull@*/ kru_registry *self, const char *name, kru_suite_setup_proc setup, kru_suite_teardown_proc teardown);

/*! \fn void kru_registry_run(kru_registry *self)
	\brief The test runner.
	\param self The test registry to run.

    This function runs the test suites and, in turn,
    the tests in them.
*/
extern void kru_registry_run(/*@notnull@*/ kru_registry *self);

/*! \typedef int (*kru_format_proc)(const char *format, ...)
	\brief The report formatter.
	\param format The 'printf' compatible fromat control string.
*/
typedef int (*kru_format_proc)(const char *format, ...);

/*! \fn int kru_default_format(const char *format, ...)
	\brief The default report formatter.
	\param format The 'printf' compatible fromat control string.

	This function outputs everything to 'stderr' stream
	so the tests' output and the library's output can be
	separated.
*/
extern int kru_default_format(const char *format, ...);

/*! \fn kru_format_proc kru_registry_set_format_proc(kru_registry *self, kru_format_proc format_proc)
	\brief Sets up a new format procedure for the test registry.
	\param self The test registry to change the format
	procedure for.
	\param format_proc The new format procedure.
	\return The old format procedure.
	\warning The function assumes format_proc to be a valid
	function pointer. It aborts if format_proc is NULL.
*/
extern kru_format_proc kru_registry_set_format_proc(kru_registry *self, kru_format_proc format_proc);

/*! \fn void kru_registry_print_report(kru_registry *self)
	\brief Prints test run statistics.
	\param self The test registry to report statistics.
	\warning If you run this function without running tests,
    it will report nonsense.
*/
extern void kru_registry_print_report(/*@notnull@*/ kru_registry *self);

/*! \fn void heap_valid_report(void)
	\brief Open Watcom specific heap validity report routine.
	\warning Do not try to use it with other compilers.
 */
extern void heap_valid_report(void);

#endif /*__kru_h__*/
